﻿using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.UI;
using System.Web.UI.WebControls;
using DigibizAdvancedMediaPicker;
using DigibizTree;
using umbraco.BusinessLogic;
using umbraco.cms.businesslogic.media;
using umbraco.cms.businesslogic.datatype;
using umbraco.DataLayer;
using umbraco.interfaces;
using umbraco.cms.businesslogic.datatype.controls;
using System.Web.UI.HtmlControls;
using umbraco.IO;
using System.IO;
using System.Drawing;
using System.Drawing.Imaging;
using System.Drawing.Drawing2D;
using System.Xml;
using umbraco.cms.businesslogic.web;

namespace DAMP.Samples
{
    public partial class Installer : System.Web.UI.UserControl
    {
        private static readonly int LABEL_DATATYPE_ID = -92;
        private static readonly int UPLOAD_DATATYPE_ID = -90;
        private static readonly string CROP_WIDE_DATATYPE_NAME = "Crop - Wide sample";
        private static readonly string CROP_LONG_DATATYPE_NAME = "Crop - Long sample";
        private static readonly string DAMP_WIDE_DATATYPE_NAME = "DAMP 2.5 - New wide sample";
        private static readonly string DAMP_LONG_DATATYPE_NAME = "DAMP 2.5 - New long sample";
        private static readonly string FOLDER_MEDIATYPE_NAME = "Folder";
        private static readonly string IMAGE_MEDIATYPE_NAME = "Image";
        private static readonly string FILE_MEDIATYPE_NAME = "File";
        private static readonly string DAMP_NODE_NAME = "DAMP 2.5 Sample page";

        public IDataType uploadField = new Factory().GetNewObject(new Guid("5032a6e6-69e3-491d-bb28-cd31cd11086c"));

        public string RedirectId
        {
            get;
            set;
        }

        protected static ISqlHelper SqlHelper
        {
            get
            {
                return umbraco.BusinessLogic.Application.SqlHelper;
            }
        }

        protected void Page_Load(object sender, EventArgs e)
        {
            if (!IsPostBack)
            {
                Install();
            }
        }

        private void Install()
        {
            try
            {
                //Create Image MediaTypes with crop.

                User adminUser = new User(0);

                MediaType imageWide = CreateMediaType(adminUser, "ImageWide", CROP_WIDE_DATATYPE_NAME, "wideImage", "Wide image");
                MediaType imageLong = CreateMediaType(adminUser, "ImageLong", CROP_LONG_DATATYPE_NAME, "longImage", "Long image");

                //Add new MediaTypes to the folder Allowed child nodetypes.
                MediaType folder = MediaType.GetByAlias(FOLDER_MEDIATYPE_NAME);

                int[] folderStructure = folder.AllowedChildContentTypeIDs;
                int newsize = folderStructure.Count() + 2;

                Array.Resize(ref folderStructure, newsize);
                folderStructure[newsize - 2] = imageWide.Id;
                folderStructure[newsize - 1] = imageLong.Id;

                folder.AllowedChildContentTypeIDs = folderStructure;
                folder.Save();

                //Create media items.

                //File
                MediaType file = MediaType.GetByAlias(FILE_MEDIATYPE_NAME);
                Media file1 = CreateMedia(-1, "Digibiz_EN", "Digibiz_EN.pdf", file, adminUser, File.ReadAllBytes(HttpContext.Current.Server.MapPath("/umbraco/plugins/DigibizAdvancedMediaPicker/Samples/Digibiz_EN.pdf")), false);
                Media file2 = CreateMedia(-1, "Digibiz_NL", "Digibiz_NL.pdf", file, adminUser, File.ReadAllBytes(HttpContext.Current.Server.MapPath("/umbraco/plugins/DigibizAdvancedMediaPicker/Samples/Digibiz_NL.pdf")), false);

                //Classic
                MediaType image = MediaType.GetByAlias(IMAGE_MEDIATYPE_NAME);
                Media image1 = CreateMedia(-1, "Image classic 1", "image1.jpg", image, adminUser, File.ReadAllBytes(HttpContext.Current.Server.MapPath("/umbraco/plugins/DigibizAdvancedMediaPicker/Samples/Jellyfish.jpg")), true);

                //New wide
                Media folderWide = Media.MakeNew("Wide images", folder, adminUser, -1);
                Media imageWide1 = CreateMedia(folderWide.Id, "Image new wide 1", "image2.jpg", imageWide, adminUser, File.ReadAllBytes(HttpContext.Current.Server.MapPath("/umbraco/plugins/DigibizAdvancedMediaPicker/Samples/Hydrangeas.jpg")), true);
                Media imageWide2 = CreateMedia(folderWide.Id, "Image new wide 2", "image3.jpg", imageWide, adminUser, File.ReadAllBytes(HttpContext.Current.Server.MapPath("/umbraco/plugins/DigibizAdvancedMediaPicker/Samples/Tulips.jpg")), true);
                Media imageWide3 = CreateMedia(folderWide.Id, "Image new wide 3", "image4.jpg", imageWide, adminUser, File.ReadAllBytes(HttpContext.Current.Server.MapPath("/umbraco/plugins/DigibizAdvancedMediaPicker/Samples/Chrysanthemum.jpg")), true);

                //New long
                Media folderLong = Media.MakeNew("Long images", folder, adminUser, -1);
                Media imageLong1 = CreateMedia(folderLong.Id, "Image new long 1", "image5.jpg", imageLong, adminUser, File.ReadAllBytes(HttpContext.Current.Server.MapPath("/umbraco/plugins/DigibizAdvancedMediaPicker/Samples/Penguins.jpg")), true);
                Media imageLong2 = CreateMedia(folderLong.Id, "Image new long 2", "image6.jpg", imageLong, adminUser, File.ReadAllBytes(HttpContext.Current.Server.MapPath("/umbraco/plugins/DigibizAdvancedMediaPicker/Samples/Tulips.jpg")), true);

                //Update the prevalues

                int dampWideId = GetIdByName(DAMP_WIDE_DATATYPE_NAME);
                int dampLongId = GetIdByName(DAMP_LONG_DATATYPE_NAME);

                DataTypeDefinition dampWide = DataTypeDefinition.GetDataTypeDefinition(dampWideId);
                DataTypeDefinition dampLong = DataTypeDefinition.GetDataTypeDefinition(dampLongId);

                DAMP_PrevalueEditor widePrevalueEditor = (DAMP_PrevalueEditor)dampWide.DataType.PrevalueEditor;
                DAMP_PrevalueEditor longPrevalueEditor = (DAMP_PrevalueEditor)dampLong.DataType.PrevalueEditor;

                SortedList widePrevalues = widePrevalueEditor.GetPreValues();
                SortedList longPrevalues = longPrevalueEditor.GetPreValues();

                widePrevalueEditor.SavePreValue(DAMP_PrevalueEditor.PropertyIndex.StartNodeId, folderWide.Id.ToString(), widePrevalues);
                widePrevalueEditor.SavePreValue(DAMP_PrevalueEditor.PropertyIndex.AllowedSelectableMediaTypes, imageWide.Id.ToString(), widePrevalues);
                widePrevalueEditor.SavePreValue(DAMP_PrevalueEditor.PropertyIndex.AllowedCreateableMediaTypes, imageWide.Id.ToString(), widePrevalues);
                widePrevalueEditor.SavePreValue(DAMP_PrevalueEditor.PropertyIndex.DefaultMediaType, imageWide.Id.ToString(), widePrevalues);

                longPrevalueEditor.SavePreValue(DAMP_PrevalueEditor.PropertyIndex.AllowedSelectableMediaTypes, imageLong.Id.ToString(), longPrevalues);
                longPrevalueEditor.SavePreValue(DAMP_PrevalueEditor.PropertyIndex.AllowedCreateableMediaTypes, imageLong.Id.ToString(), longPrevalues);
                longPrevalueEditor.SavePreValue(DAMP_PrevalueEditor.PropertyIndex.DefaultMediaType, imageLong.Id.ToString(), longPrevalues);

                //Save the media items in the node.

                int nodeId = GetIdByName(DAMP_NODE_NAME);
                Document document = new Document(nodeId);

                string[] fileIds = new string[] { file1.Id.ToString() };
                string[] wideIds = new string[] { imageWide1.Id.ToString(), imageWide2.Id.ToString(), imageWide3.Id.ToString() };
                string[] longIds = new string[] { imageLong1.Id.ToString(), imageLong2.Id.ToString() };

                document.getProperty("dampFile").Value = DigibizMediaHelper.GetXML(fileIds).ToString();
                document.getProperty("dampClassic").Value = image1.Id.ToString();
                document.getProperty("dampNewWide").Value = DigibizMediaHelper.GetXML(wideIds).ToString();
                document.getProperty("dampNewLong").Value = DigibizMediaHelper.GetXML(longIds).ToString();

                document.Save();

                document.Publish(adminUser);
                umbraco.library.UpdateDocumentCache(document.Id);

                //Copy the view if it exists.
                string path = HttpContext.Current.Server.MapPath("/umbraco/plugins/DigibizAdvancedMediaPicker/Samples/DAMPSample.cshtml");
                if (File.Exists(path))
                {
                    File.Copy(path, HttpContext.Current.Server.MapPath("/Views/DAMPSample.cshtml"));
                }

                //Store the node id in this property so we can redirect to the page.
                RedirectId = nodeId.ToString();
                
            }
            catch (Exception ex)
            {
                DAMP_Helper.LogException(ex);
            }
        }

        /// <summary>
        /// Create a Media Type.
        /// </summary>
        /// <param name="adminUser"></param>
        /// <param name="mediaTypeName"></param>
        /// <param name="cropDataTypeName"></param>
        /// <param name="cropProperty"></param>
        /// <param name="cropName"></param>
        /// <returns></returns>
        private MediaType CreateMediaType(User adminUser, string mediaTypeName, string cropDataTypeName, string cropProperty, string cropName)
        {
            MediaType mediaType = MediaType.MakeNew(adminUser, mediaTypeName);

            int imageTab = mediaType.AddVirtualTab("Image");
            int cropTab = mediaType.AddVirtualTab("Crop");
            int cropId = GetIdByName(cropDataTypeName);

            mediaType.AddPropertyType(new DataTypeDefinition(UPLOAD_DATATYPE_ID), "umbracoFile", "Upload image");
            mediaType.AddPropertyType(new DataTypeDefinition(LABEL_DATATYPE_ID), "umbracoWidth", "Width");
            mediaType.AddPropertyType(new DataTypeDefinition(LABEL_DATATYPE_ID), "umbracoHeight", "Height");
            mediaType.AddPropertyType(new DataTypeDefinition(LABEL_DATATYPE_ID), "umbracoBytes", "Size");
            mediaType.AddPropertyType(new DataTypeDefinition(LABEL_DATATYPE_ID), "umbracoExtension", "Type");
            mediaType.AddPropertyType(new DataTypeDefinition(cropId), cropProperty, cropName);

            mediaType.SetTabOnPropertyType(mediaType.getPropertyType("umbracoFile"), imageTab);
            mediaType.SetTabOnPropertyType(mediaType.getPropertyType("umbracoWidth"), imageTab);
            mediaType.SetTabOnPropertyType(mediaType.getPropertyType("umbracoHeight"), imageTab);
            mediaType.SetTabOnPropertyType(mediaType.getPropertyType("umbracoBytes"), imageTab);
            mediaType.SetTabOnPropertyType(mediaType.getPropertyType("umbracoExtension"), imageTab);
            mediaType.SetTabOnPropertyType(mediaType.getPropertyType(cropProperty), cropTab);

            mediaType.Text = mediaTypeName;
            mediaType.IconUrl = "mediaPhoto.gif";
            mediaType.Save();

            return mediaType;
        }

        /// <summary>
        /// Create a media item.
        /// </summary>
        /// <param name="parentId"></param>
        /// <param name="name"></param>
        /// <param name="fileName"></param>
        /// <param name="mediaType"></param>
        /// <param name="adminUser"></param>
        /// <param name="bytes"></param>
        /// <param name="isImage"></param>
        /// <returns></returns>
        private Media CreateMedia(int parentId, string name, string fileName, MediaType mediaType, User adminUser, byte[] bytes, bool isImage)
        {
            Media media = Media.MakeNew(name, mediaType, adminUser, parentId);

            string sql = string.Format(@"
                        select cpd.id as id from cmsPropertyData cpd
                            inner join cmsPropertyType cpt on cpd.propertytypeid = cpt.Id
                            inner join cmsDataType cdt on cpt.dataTypeId = cdt.nodeId
                        where cpd.contentNodeId = {0}
                        and cdt.controlId = '{1}'", media.Id, uploadField.Id);

            int propertyId = SqlHelper.ExecuteScalar<int>(sql);

            FileInfo file = new FileInfo(IOHelper.MapPath(SystemDirectories.Media + "/" + propertyId + "/" + fileName));

            if (!file.Directory.Exists)
            {
                //If the directory doesn't exist then create it.
                file.Directory.Create();
            }

            //Write the file to the media folder.
            File.WriteAllBytes(file.FullName, bytes);

            string umbracoFile = SystemDirectories.Media + "/" + propertyId.ToString() + "/" + fileName;
            if (umbracoFile.StartsWith("~"))
            {
                umbracoFile = umbracoFile.TrimStart(new char[] { '~' });
            }

            if (media.getProperty("umbracoFile") != null)
            {
                media.getProperty("umbracoFile").Value = umbracoFile;
            }

            if (media.getProperty("umbracoExtension") != null)
            {
                media.getProperty("umbracoExtension").Value = Path.GetExtension(file.Name).Replace(".", string.Empty);
            }

            if (media.getProperty("umbracoBytes") != null)
            {
                media.getProperty("umbracoBytes").Value = bytes.Length;
            }

            if (isImage)
            {
                System.Drawing.Image image = System.Drawing.Image.FromFile(file.FullName);

                if (media.getProperty("umbracoWidth") != null)
                {
                    media.getProperty("umbracoWidth").Value = image.Width.ToString();
                }

                if (media.getProperty("umbracoHeight") != null)
                {
                    media.getProperty("umbracoHeight").Value = image.Height.ToString();
                }

                //Create a thumbnail from the image.
                string fileNameThumb = Path.Combine(file.Directory.FullName, file.Name.Replace(Path.GetExtension(file.Name), "_thumb.jpg"));
                GenerateThumbnail(image, 100, image.Width, image.Height, fileNameThumb);

                //Clean the image.
                image.Dispose();
            }

            //Save the media file to update the xml and to make sure some event's get called.
            media.Save();
            media.XmlGenerate(new XmlDocument());

            return media;
        }

        /// <summary>
        /// Return the id of an Umbraco node based on the name.
        /// </summary>
        /// <param name="name"></param>
        /// <returns></returns>
        private int GetIdByName(string name)
        {
            return SqlHelper.ExecuteScalar<int>("select id from umbracoNode where text = @name", SqlHelper.CreateParameter("@name", name));
        }

        /// <summary>
        /// Generate the thumbnail.
        /// </summary>
        /// <param name="image"></param>
        /// <param name="maxWidthHeight"></param>
        /// <param name="fileWidth"></param>
        /// <param name="fileHeight"></param>
        /// <param name="fullFilePath"></param>
        /// <param name="ext"></param>
        /// <param name="thumbnailFileName"></param>
        private void GenerateThumbnail(System.Drawing.Image image, int maxWidthHeight, int fileWidth, int fileHeight, string thumbnailFileName)
        {
            //Generate thumbnail.
            float fx = fileWidth / maxWidthHeight;
            float fy = fileHeight / maxWidthHeight;

            //Must fit in thumbnail size.
            float f = Math.Max(fx, fy); if (f < 1) f = 1;
            int widthTh = (int)(fileWidth / f); int heightTh = (int)(fileHeight / f);

            //Create new image with best quality settings.
            Bitmap bp = new Bitmap(widthTh, heightTh);
            Graphics g = Graphics.FromImage(bp);
            g.SmoothingMode = SmoothingMode.HighQuality;
            g.InterpolationMode = InterpolationMode.HighQualityBicubic;
            g.PixelOffsetMode = PixelOffsetMode.HighQuality;

            //Copy the old image to the new and resized.
            Rectangle rect = new Rectangle(0, 0, widthTh, heightTh);
            g.DrawImage(image, rect, 0, 0, image.Width, image.Height, GraphicsUnit.Pixel);

            //Copy metadata.
            ImageCodecInfo[] codecs = ImageCodecInfo.GetImageEncoders();
            ImageCodecInfo codec = null;
            for (int i = 0; i < codecs.Length; i++)
            {
                if (codecs[i].MimeType.Equals("image/jpeg"))
                    codec = codecs[i];
            }

            //Set compresion ratio to 90%.
            EncoderParameters ep = new EncoderParameters();
            ep.Param[0] = new EncoderParameter(System.Drawing.Imaging.Encoder.Quality, 90L);

            //Save the new image.
            bp.Save(thumbnailFileName, codec, ep);
            bp.Dispose();
            g.Dispose();
        }
    }
}